; int comprimir_archivo(char* archivo_entrada, char* archivo_salida);

%include "macros/personalizada.mac"
%include "macros/oc2_header_t.mac"

extern obtener_tabla_codificacion
extern comprimir_buffer
extern calcular_cant_codigos
extern malloc
extern free
extern fopen
extern fread
extern fwrite
extern ftell
extern fseek
extern fclose

global comprimir_archivo

%define tabla_codificacion_size [ebp - 28]
%define ptr_tabla_codificacion [ebp - 24]
%define longitud_codificacion [ebp - 20]
%define ptr_tabla_codigos [ebp - 16]
%define dst_size [ebp - 12]
%define ptr_dst_buf [ebp - 8]
%define ptr_src_buf [ebp - 4]
%define ruta_archivo_entrada [ebp + 8]
%define ruta_archivo_salida [ebp + 12]
%define SEEK_SET 0 ; Principio del archivo.
%define SEEK_CUR 1 ; Posicion actual del puntero del archivo.
%define SEEK_END 2 ; Fin del archivo.

section .data
	read: db 'r'
	write: db 'w'
	
section .text
	
comprimir_archivo:
	push ebp
	mov ebp, esp
	sub esp, 28
	push esi
	push edi
	push ebx
	
	; Levantamos el archivo de entrada que vamos a comprimir.
	; FILE *fp = fopen(ruta_archivo_entrada,"r");
	mov eax, read ; Lo levantamos para lectura.
	mov esi, ruta_archivo_entrada ; Esta es la ruta del archivo de entrada.
	push eax
	push esi
	call fopen
	add esp, 8
	cmp eax, 0 ; Si no puede crear el puntero al archivo devuelve NULL.
	je NEAR error
	mov esi, eax ; esi = el puntero al archivo de entrada.
	
	; Nos posicionamos en la ultima posicion del archivo.
	; int res = fseek(fp, 0, SEEK_END);
	push dword SEEK_END
	push dword 0
	push esi
	call fseek
	add esp, 12
	cmp eax, 0 ; Si la funcion tiene exito retorna el valor cero.
	jne NEAR error ; Sino retorna un valor que no es cero.
	
	; Obtenemos la posicion dentro del archivo.
	; long int res = ftell (fp);
	push esi
	call ftell
	add esp, 4
	cmp eax, error_code ; Si la funcion tiene exito retorna la posicion actual del archivo.
	je NEAR error ; Sino retorna -1 que es nuestro codigo de error (error_code).
	mov ebx, eax ; ebx = el size del archivo en bytes.

	; Nos posicionamos en la primera posicion del archivo.
	; int res = fseek(fp, 0, SEEK_SET);
	push dword SEEK_SET
	push dword 0
	push esi
	call fseek
	add esp, 12
	cmp eax, 0 ; Si la funcion tiene exito retorna el valor cero.
	jne NEAR error ; Sino retorna un valor que no es cero.
	
	; Reservamos memoria para el buffer de entrada.
	push ebx
	call malloc
	add esp, 4
	cmp eax, 0 ; Si la funcion tiene exito retorna la direccion de memoria reservada.
	je NEAR error ; Sino retorna NULL.
	mov edi, eax ; edi = el puntero al buffer de entrada.
	
	; Movemos el archivo de entrada al buffer de entrada(src_buf).
	;size_t res = fread (void * ptr, size_t size, size_t count, FILE * stream);
	push esi
	push ebx
	push dword 1
	push edi
	call fread
	add esp, 16
	cmp eax, 0 ; Si la funcion tiene exito retorna el tamaño de los datos leidos.
	je NEAR error ; Sino retorna el valor cero.
	
	; Llamamos a comprimir_buffer.
	; edi = el buffer de entrada (src_buf) y ebx = el size (scr_size).
	; int comprimir_buffer(unsigned char *scr_buf, unsigned int scr_size, 
	; 						unsigned char **dst_buf, unsigned int *dst_size, 
	;						codigo_t **tabla_codigos, unsigned int *long_codificacion);
	lea eax, longitud_codificacion
	push eax
	lea eax, ptr_tabla_codigos
	push eax
	lea eax, dst_size
	push eax
	lea eax, ptr_dst_buf
	push eax
	push ebx
	push edi
	call comprimir_buffer
	add esp, 24
	cmp eax, 0; Si la funcion tiene exito retorna 0.
	jne NEAR error ; Sino retorna un codigo de error.
	
	; Liberamos la memoria del src_buf.
	push edi
	call free
	add esp, 4
	
	; Creamos el header.
	push dword 16
	call malloc
	add esp, 4
	cmp eax, 0
	je NEAR error
	mov esi, eax ; esi = el puntero al header.
	
	; Calculamos la cantidad de codigos validos que hay en la tabla.
	; int calcular_cant_codigos(codigo_t *tabla_codigos);
	push dword ptr_tabla_codigos
	call calcular_cant_codigos
	add esp, 4
	cmp eax, 0
	je NEAR error
	mov ecx, eax ; ecx = la cantidad de codigos validos.
	
	; Calculamos el offset_codificacion.
	; Multiplicamos eax por 9 que es el tam en bytes del tipo codificacion_t.
	mov edx, 9
	mul edx
	
	; Sumamos ahora el tamaño del header
	add eax, 16
	
	; Completamos el header.
	mov [esi + off_tam_original_h], ebx
	mov [esi + off_cant_codigos_h], ecx
	mov [esi + off_offset_codificacion_h], eax
	mov eax, longitud_codificacion
	mov [esi + off_long_codificacion_h], eax
	
	mov ebx, ecx ; ebx = Guardamos la cantidad de codigos validos en la tabla.
	
	; Levantamos el archivo de salida que vamos a comprimir.
	; FILE *fp = fopen(ruta_archivo_salida,"r");
	mov eax, write ; Lo levantamos para escritura.
	mov edi, ruta_archivo_salida ; Esta es la ruta del archivo de salida.
	push eax
	push edi
	call fopen
	add esp, 8
	cmp eax, 0 ; Si no puede crear el puntero al archivo devuelve NULL.
	je NEAR error
	mov edi, eax ; edi = el puntero al archivo de salida.
	
	; Movemos el header al archivo de salida.
	;size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
	push edi
	push dword 1
	push dword 16 ; El tamaño del header
	push esi
	call fwrite
	add esp, 16
	cmp eax, 0
	je NEAR error
	
	; Liberamos la memoria del header.
	push esi
	call free
	add esp, 4
	
	; Llamamos a obtener_tabla_codificacion.
	; int obtener_tabla_codificacion(codigo_t *tabla_codigos, 
	;									unsigned int cant_codigos,
	;									codificacion_t **ptr_tabla_codificacion, 
	;									unsigned int *tabla_codificacion_size);
	lea eax, tabla_codificacion_size
	push eax
	lea eax, ptr_tabla_codificacion
	push eax
	push ebx
	mov eax, ptr_tabla_codigos
	push eax
	call obtener_tabla_codificacion
	add esp, 16
	cmp eax, 0; Si la funcion tiene exito retorna 0.
	jne NEAR error ; Sino retorna un codigo de error.
	
	; Movemos la tabla de codificacion al archivo.
	
	;size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
	mov esi, ptr_tabla_codificacion
	mov ecx, tabla_codificacion_size
	push edi
	push dword 1
	push ecx
	push esi
	call fwrite
	add esp, 16
	cmp eax, 0
	je error
	
	; Liberamos la memoria de la tabla de codigos.
	mov eax, ptr_tabla_codigos
	push eax
	call free
	add esp, 4
	
	; Liberamos la memoria de la tabla de codificacion.
	mov eax, ptr_tabla_codificacion
	push eax
	call free
	add esp, 4
	
	;size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
	mov esi, ptr_dst_buf
	mov ecx, dst_size
	push edi
	push dword 1
	push ecx
	push esi
	call fwrite
	add esp, 16
	cmp eax, 0
	je error
	
	;Liberamos la memoria del dst_buff
	push esi
	call free
	add esp,4
	
	mov eax, 1; La funcion termino con exito y retorna 1.
	
	jmp fin
	
error:
	xor eax, eax ; La funcion fallo y retorna 0 como codigo de error.
	
fin:
	pop ebx
	pop edi
	pop esi
	add esp, 28
	pop ebp
	ret
